//
//  Interactor.swift
//  DYSwiftFramework
//
//  Created by 黄德玉 on 2018/8/16.
//  Copyright © 2018年 none. All rights reserved.
//

import UIKit

public enum InteractorDirection {
    case left                   // 向左滑
    case right                  // 向右滑
    case up                     // 向上滑
    case down                   // 向下滑
}


public class Interactor: UIPercentDrivenInteractiveTransition,UIGestureRecognizerDelegate {
    public var canInteractive = true
    
    public var speedControl:CGFloat = 1.0;                      // 1.0:手指滑动1cm,UI变化1cm.   0.5:手指滑动1cm,UI变动0.5cm
    public var edgeSpace:CGFloat = 60.0;                        // 触发转场手指距离边缘的距离,必须小于这个距离 才能触发手势，（如果是screenWidth，那么是全局侧滑）
    public var canOverPercent:CGFloat = 0.5;                    // 滑动触发百分比大于等于0.5就自动完成侧滑
    public var canOverVelocity:CGFloat?                 // 滑动速度超过一定速度就会完成侧滑
    public var direction:InteractorDirection          // 滑动方向
    
    private var gesture = UIPanGestureRecognizer(target: self, action: #selector(gestureAction(gesture:)))
    private var percent:CGFloat = 0.0;
    private var startPoint = CGPoint(x: 0, y: 0)
    
    // 在 init 中 有四个阶段的安全检查, 这里违背了第四个检查
    // 初始化 编译的过程的四个安全检查
    // 1. 在调用父类初始化之前 必须给子类特有的属性设置初始值, 只有在类的所有存储属性状态都明确后, 这个对象才能被初始化
    // 2. 先调用父类的初始化方法,  再 给从父类那继承来的属性初始化值, 不然这些属性值 会被父类的初始化方法覆盖
    // 3. convenience 必须先调用 designated 初始化方法, 再 给属性初始值. 不然设置的属性初始值会被 designated 初始化方法覆盖
    // 4. 在第一阶段完成之前, 不能调用实类方法, 不能读取属性值, 不能引用self

    init(direction:InteractorDirection) {
        self.direction = direction
        super.init()
        gesture.delegate = self
    }
    
    
    // 手势事件
    @objc public func gestureAction(gesture:UIPanGestureRecognizer){
        switch gesture.state {
        case .began:
            startPoint = gesture.translation(in: gesture.view)          // 不能用 localtionInView
            percent = 0
            canInteractive  = true
            ////
            // 这里应该加上页面切换逻辑，present ,push ,pop ,dismiss的操作需要在这里执行
            ////
        case .changed:
            caculatePercent()
        case .ended,.cancelled,.failed:
            canInteractive = false
            caculateEnd()
        default:
            break
        }
    }
    
    // 根据手势驱动 计算当前滑动百分比
    private func caculatePercent(){
        let view = gesture.view!
        let point = gesture.translation(in: view)
        switch direction {
        case .up:
            percent = (startPoint.y - point.y) / view.frame.size.height
        case .left:
            percent = (startPoint.x - point.x) / view.frame.size.width
        case .down:
            percent = (point.y - startPoint.y) / view.frame.size.height
        case .right:
            percent = (point.x - startPoint.x) / view.frame.size.width
        }
        
        percent = percent * speedControl    //根据速率来计算当前percent
        percent = percent < 0 ? 0 : percent
        percent = percent > 1 ? 1 : percent
        update(percent)                     //更新转场百分比
    }
    
    // 手势结束后，计算是否需要完成转场
    private func caculateEnd(){
        if percent > canOverPercent{
            finish()
            return
        }
        if let overVec = canOverVelocity {
            let velocity = gesture.velocity(in: gesture.view)
            var directVelocity:CGFloat = 0.0
            switch direction {
            case .up,.down:
                directVelocity = fabs(velocity.y)
            default:
                directVelocity = fabs(velocity.x)
            }
            //这边定义一个约束，如果根据速度判断是否完成或者取消转场的话，必须满足大于percent的.66倍才能转场
            if overVec > directVelocity && percent > canOverPercent * 0.66 {
                finish()
            }else{
                cancel()
            }
        } else {
            cancel()
        }
    }
    
    // gesture delegate
    public func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
        // 连续多次滑动会影响结束或取消过程,判断当前有速度的情况下禁止再加入滑动手势                --------------------  这是一个大坑
        if percentComplete != 0 {
            return false;
        }
        // 判断初始点的位置是否满足侧滑条件：edgeSpace
        let tempStartPoint = gestureRecognizer.location(in: nil)
        switch direction {
        case .up:
            if (tempStartPoint.y + edgeSpace < UIScreen.main.bounds.height) {
                return false
            }
        case .left:
            if tempStartPoint.x + edgeSpace < UIScreen.main.bounds.width {
                return false
            }
        case .down:
            if tempStartPoint.y > edgeSpace  {
                return false
            }
        case .right:
            if tempStartPoint.x < edgeSpace {
                return false
            }
        }
        return true;
    }
    
}













